#include "llamar.h"

Llamar::Llamar(Sentencia *next, vector<Expr *> expr, string lexema, int fila, int col):Sentencia(next,fila,col)
{
    this->expr = expr;
    this->lexema = lexema;
}

string Llamar::is()
{
    return "LLAMAR";
}

void Llamar::setExpr(vector<Expr *> expr)
{
    this->expr=expr;
}

vector<Expr *> Llamar::getExpr()
{
    return this->expr;
}

void Llamar::setLexema(string lexema)
{
    this->lexema = lexema;
}

string Llamar::getLexema()
{
    return this->lexema;
}

Tipo_ts *Llamar::validarSemantica(Tabla_Simbolos *tabla_de_tipo, Tabla_Simbolos *tabla_de_varaible)
{
    Item_ts *its = tabla_de_varaible->get(this->lexema.append("&FP&"));
    if(its!=0){
        if(its->getTipo()->is().compare("PROCEDIMIENTO")==0 || its->getTipo()->is().compare("FUNCION")==0){

            if(its->getTipo()->is().compare("PROCEDIMIENTO")==0 ){
                Procedimiento *pro = (Procedimiento*)its->getTipo();
                if(pro->getParams()->getTable().size()==this->expr.size()){
                    for(int i = 0; i<(int)this->expr.size();i++){
                        Tipo_ts *tts_ = this->expr.at(i)->validarSemantica(tabla_de_tipo,tabla_de_varaible);
                        if(pro->getParams()->getTable().at(i)->getTipo()->is().compare(tts_->is())!=0){
                            if((pro->getParams()->getTable().at(i)->getTipo()->is().compare("REAL")==0 || pro->getParams()->getTable().at(i)->getTipo()->is().compare("ENTERO")==0)&&(tts_->is().compare("REAL")==0||tts_->is().compare("ENTERO")==0)){

                            }else{
                                stringstream out;
                                out<<"Parametros son de difernete tipo: ";
                                out<<this->expr.at(i)->is()<< " // Fila:"<<this->getFila()<<endl;
                                throw exception(out.str().c_str());
                            }

                        }else{
                            if(pro->getParams()->getTable().at(i)->getVar()){
                                if(this->getExpr().at(i)->is().compare("Literal_Identificador")!=0){
                                    stringstream out;
                                    out<<"Se Esperaba un literal indenditficador dentro del parametro// Fila:"<<this->getFila()<<endl;
                                    throw exception(out.str().c_str());
                                }

                            }

                        }
                    }


                }else{
                    stringstream out;
                    out<<"Cantidad de Parametros no coinciden// Fila:"<<this->getFila()<<endl;
                    throw exception(out.str().c_str());
                }
            }else{
                Funcion *pro = (Funcion*)its->getTipo();
                if(pro->getParams()->getTable().size()==this->expr.size()){
                    for(int i = 0; i<(int)this->expr.size();i++){
                        Tipo_ts *tts_ = this->expr.at(i)->validarSemantica(tabla_de_tipo,tabla_de_varaible);

                        if(pro->getParams()->getTable().at(i)->getTipo()->is().compare(tts_->is())!=0){
                            if((pro->getParams()->getTable().at(i)->getTipo()->is().compare("REAL")==0 || pro->getParams()->getTable().at(i)->getTipo()->is().compare("ENTERO")==0)&&(tts_->is().compare("REAL")==0||tts_->is().compare("ENTERO")==0)){

                            }else{
                                stringstream out;
                                out<<"Parametros son de difernete tipo: ";
                                out<<this->expr.at(i)->is()<< " // Fila:"<<this->getFila()<<endl;
                                throw exception(out.str().c_str());
                            }
                        }else{
                            if(pro->getParams()->getTable().at(i)->getVar()){
                                if(this->getExpr().at(i)->is().compare("Literal_Identificador")!=0){
                                    stringstream out;
                                    out<<"Se Esperaba un literal indenditficador dentro del parametro// Fila: "<<this->getFila()<<endl;
                                    throw exception(out.str().c_str());
                                }

                            }
                        }

                    }


                }else{
                    stringstream out;
                    out<<"Cantidad de Parametros no coinciden// Fila: "<<this->getFila()<<endl;
                    throw exception(out.str().c_str());
                }
            }


        }else{
            stringstream out;
            out<<"Se esperaba un procedimiento o Funcion// Fila: "<<this->getFila()<<endl;
            throw exception(out.str().c_str());
        }

    }else{
        stringstream out;
        out<<"Procedimiento o Funcion No Existe "<<this->getLexema()<< " // Fila: "<<this->getFila()<<endl;
        throw exception(out.str().c_str());
    }
    if(this->getNext()!=0){
        this->getNext()->SetReturn(this->GetReturn());
        this->getNext()->validarSemantica(tabla_de_tipo,tabla_de_varaible);
    }
    return 0;
}

string Llamar::generarCodigo(GenerarVariable *var, Tabla_Simbolos *tabla_de_tipo, Tabla_Simbolos *tabla_de_varaible)
{
    string codigo = "_"+this->getLexema()+"_(";
    for(int i = 0 ; i < this->getExpr().size();i++){
        codigo += this->getExpr().at(i)->generarCodigo(var,tabla_de_tipo,tabla_de_varaible).codigo+",";
    }
    codigo = codigo.substr(0,codigo.size()-1);
    codigo += ");\n";
    if(this->getNext()!=0){
        codigo += this->getNext()->generarCodigo(var,tabla_de_tipo,tabla_de_varaible);
    }
    return codigo;
}
